package com.tbit.uqbike.webmanager.controller;

import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tbit.common.constant.MethodEnum;
import com.tbit.common.constant.ModuleEnum;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.annos.OperateLog;
import com.tbit.uqbike.constant.HttpStatus;
import com.tbit.uqbike.constant.UserConstant;
import com.tbit.uqbike.enums.SystemCodeEnum;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.EditOrderDTO;
import com.tbit.uqbike.object.pojo.dto.RideLogDownloadDTO;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.object.value.Page;
import com.tbit.uqbike.object.view.JsonResult;
import com.tbit.uqbike.service.base.HistoryService;
import com.tbit.uqbike.service.base.MachineService;
import com.tbit.uqbike.service.base.TokenService;
import com.tbit.uqbike.service.business.AccountService;
import com.tbit.uqbike.service.business.RideLogDetailsService;
import com.tbit.uqbike.service.business.RideLogService;
import com.tbit.uqbike.service.business.UserService;
import com.tbit.uqbike.webmanager.util.*;
import com.tbit.uqbike.webmanager.util.csv.annotations.AsyncDownload;
import com.tbit.utils.Excel;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 骑行记录
 *
 * @author Leon
 * 2017年2月24日 下午5:51:05
 */
@Validated
@RestController
@RequestMapping(value = "/ridelog", produces = BaseController.MEDIA_JSON_UTF8)
public class RideLogController extends BaseController {
    @Autowired
    private AccountService accountService;
    @Autowired
    private RideLogService rideLogService;
    @Autowired
    private UserService userService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private RideLogDetailsService rideLogDetailsService;
    @Resource
    private HistoryService historyService;
    @Autowired
    private TokenService tokenService;

    /**
     * 分页查询
     *
     * @param sortName  排序
     * @param sign      签名
     * @param rowCount  分页条数
     * @param pageNO    页码
     * @param userId    用户id
     * @param phone     手机号
     * @param machineId 设备id
     * @param userCode  车辆编号
     * @param request   请求
     * @return unknown
     */
    @RequestMapping("/queryPage")
    public JsonResult queryPage(String sortName,
                                @RequestParam(defaultValue = "1") Integer sign,
                                @RequestParam(defaultValue = "10") Integer rowCount,
                                @RequestParam(defaultValue = "1") Integer pageNO,
                                Integer userId, String phone, Integer machineId, String userCode, String orderNo,
                                HttpServletRequest request) {
        LoginInfo loginInfo = getLogin(request);
        Integer accountId;
        List<Integer> adAccountIdList = new ArrayList<>();
        if (loginInfo.type.equals(UserConstant.USER_ADMIN)) {
            accountId = null;
        } else if (loginInfo.type.equals(UserConstant.USER_BRAND)) {
            accountId = loginInfo.id;
        } else if (loginInfo.type.equals(UserConstant.USER_FRANCHISEE)) {
            accountId = accountService.getById(loginInfo.id).getParentId();
            adAccountIdList = accountService.getByParentId(loginInfo.id);
        } else {
            adAccountIdList.add(loginInfo.id);
            accountId = accountService.getAgentId(loginInfo.id).getParentId();
        }
        if (phone == null && userCode == null && orderNo == null) {
            throw new BaseException("手机号、车辆编号和订单号不能都为空");
        }
        List<Integer> userIds = new ArrayList<>();
        List<User> users;
        if (phone != null) {
            users = userService.getByAccountIdAndPhone(accountId, phone);
            if (users == null || users.size() < 1) {
                throw new BaseException(SystemCodeEnum.USER_NOT_EXIT);
            } else {
                for (User user : users) {
                    userIds.add(user.getUserId());
                }
            }
        }
        if (userCode != null) {
            Machine machine = machineService.getByUserCode(userCode);
            if (machine == null) {
                throw new BaseException("machine_not_exist");
            }
            //如果不是管理员账号登录，判断这辆车是否是这个品牌下的车
            if (accountId != null) {
                Integer brandId = accountService.getBrandId(machine.getAccountId());
                if (!Objects.equals(accountId, brandId)) {
                    throw new BaseException("machine_not_exist");
                }
            }
            machineId = machine.getMachineId();
        }
        if (StrUtil.isNotEmpty(orderNo)) {
            RideLog byOrderNO = rideLogService.getByOrderNO(orderNo);
            if (Objects.isNull(byOrderNO)) {
                throw new BaseException("订单编号不存在");
            }
        }
        if (sortName != null && !"".equals(sortName)) {
            sortName = sortName + (sign == 1 ? " asc" : " desc");
        }
        /*获取总数*/
        Integer total = rideLogService.queryCount(userIds, machineId, adAccountIdList, orderNo);
        /*当前返回行数*/
        List<RideLog> rideLogs = rideLogService.queryPage(userIds, machineId, rowCount, pageNO, sortName, adAccountIdList, orderNo);

        return JsonResult.ok(rideLogs, total);
    }

    /**
     * 通过设备id查询订单记录
     */
    @RequestMapping("/getByMachineId")
    public JsonResult getByMachineId(@NotNull(message = "ver.machineId.notNull") Integer machineId,
                                     String phone, String orderNo, @RequestParam(defaultValue = "5") Integer rowCount,
                                     @RequestParam(defaultValue = "1") Integer pageNO) {
        if (pageNO <= 0) {
            pageNO = 1;
        }
        Integer total = rideLogService.getByMachineIdCount(machineId, phone, orderNo);
        if (total <= 0) {
            return JsonResult.ok(Collections.emptyList(), total);
        }
        List<MachineRideLog> list = rideLogService.getByMachineId(machineId, phone, orderNo, rowCount, pageNO);
        if (CollectionUtils.isNotEmpty(list)) {
            MachineRideLog machineRideLog = list.get(0);
            if (machineRideLog.onRiding()) {
                Double mileage = historyService.getMileageByMachineNoAndTime(machineRideLog.getMachineNO(),
                        machineRideLog.getStartTime().getTime(), System.currentTimeMillis());
                machineRideLog.setMileage(mileage);
            }
        }
        return JsonResult.ok(list, total);
    }

    /**
     * 通过userId查询订单记录
     *
     * @param userId  用户id
     * @param orderNo 订单号
     */
    @RequestMapping("/getByUserId")
    public JsonResult getByUserId(@NotNull(message = "ver.userId.notNull") Integer userId, String orderNo,
                                  @RequestParam(defaultValue = "5") Integer rowCount,
                                  @RequestParam(defaultValue = "1") Integer pageNO,
                                  String accountIds) {
        if (pageNO <= 0) {
            pageNO = 1;
        }
        List<Integer> accountIdList = StringUtils.str2List(accountIds, ",", true, true)
                .stream().map(Integer::parseInt).collect(Collectors.toList());
        PageHelper.startPage(pageNO, rowCount);
        List<MachineRideLog> list = rideLogService.getByUserId(userId, orderNo, accountIdList);
        if (CollectionUtils.isNotEmpty(list)) {
            MachineRideLog machineRideLog = list.get(0);
            if (machineRideLog.onRiding()) {
                Double mileage = historyService.getMileageByMachineNoAndTime(machineRideLog.getMachineNO(),
                        machineRideLog.getStartTime().getTime(), System.currentTimeMillis());
                machineRideLog.setMileage(mileage);
            }
        }
        PageInfo<MachineRideLog> pageInfo = new PageInfo<>(list);
        return JsonResult.ok(pageInfo.getList(), (int) pageInfo.getTotal());
    }

    /**
     * 通过userId查询订单记录
     *
     * @param userId 最近骑行订单的区域
     */
    @RequestMapping("/getAccountByUserOrder")
    public Result<List<Account>> getAccountByUserOrder(@NotNull(message = "ver.userId.notNull") Integer userId) {
        LoginInfo login = BaseController.getLogin(ServletUtils.getRequest());
        List<Integer> accountIdList = accountService.getAccountByLoginUser(login)
                .stream().filter(account -> account.getAccountId() != -1)
                .map(Account::getAccountId).collect(Collectors.toList());
        Account accountFirst = rideLogService.getAccountByUserOrder(userId, accountIdList);
        List<Account> accountListBind = accountService.getAccountByUserBind(userId);
        accountListBind = accountListBind.stream()
                .filter(account -> account.getAccountId() != -1)
                .filter(account -> !Objects.equals(accountFirst.getAccountId(), account.getAccountId()))
                .collect(Collectors.toList());

        List<Account> accountList = new ArrayList<>();
        accountList.add(accountFirst);
        accountList.addAll(accountListBind);
        return Result.success(accountList);
    }

    /**
     * 通过设备编号查询骑行里程
     */
    @GetMapping("/getMileageByMachineNo")
    public Result<Double> getMileageByMachineNo(@NotNull(message = "ver.machineNO.notNull") String machineNo,
                                                @NotNull(message = "ver.startTime.notNull") Long startTime,
                                                @NotNull(message = "ver.endTime.notNull") Long endTime
    ) {
        Double mileage = historyService.getMileageByMachineNoAndTime(machineNo, startTime, endTime);
        return Result.success(mileage);
    }

    /**
     * 查询订单记录详细
     */
    @RequestMapping("/rechargeQueryPage")
    public JsonResult rechargeQueryPage(@NotNull(message = "ver.areaId.notNull") Integer accountId,
                                        @NotNull(message = "ver.startTime.notNull") Long startTime,
                                        @NotNull(message = "ver.endTime.notNull") Long endTime,
                                        Integer type, String phone, String userCode, String orderNO, Integer timeType,
                                        @RequestParam(defaultValue = "10") Integer rowCount, Integer ridingTimeMoreThan,
                                        @RequestParam(defaultValue = "1") Integer pageNO, HttpServletRequest request,
                                        @RequestParam(required = false, value = "regionIds") String regionIds) {
        Role role = getLogin(request).getRoles().get(0);
        List<Integer> regionList = StringUtil.getIntegerList(regionIds);
        List<RideLog> list = rideLogService.rechargeQueryPage(new HashMap<>(), accountId, type, startTime, endTime, phone, userCode, orderNO, pageNO, rowCount, role, regionList, timeType, ridingTimeMoreThan);
        Integer total = rideLogService.rechargeQueryCount(new HashMap<>(), accountId, type, startTime, endTime, phone, userCode, orderNO, role, regionList, timeType, ridingTimeMoreThan);
        return JsonResult.ok(list, total, ridingTimeMoreThan);
    }

    /**
     * 订单记录详细导出CSV
     */
    @AsyncDownload(defaultFileName = "订单记录详细导出")
    @RequestMapping("/rechargeQueryExport")
    public Result<String> rechargeQueryExportCsv(RideLogDownloadDTO downloadDTO) {
        if (Objects.isNull(downloadDTO.getAccountId())) {
            return Result.error("ver.adAccountId.notNull");
        }
        if (Objects.isNull(downloadDTO.getStartTime())) {
            return Result.error("ver.startTime.notNull");
        }
        if (Objects.isNull(downloadDTO.getEndTime())) {
            return Result.error("ver.endTime.notNull");
        }
        LoginInfo login = tokenService.getLoginInfo(downloadDTO.getToken());
        Role role = login.getRoles().get(0);
        List<Integer> regionList = StringUtil.getIntegerList(downloadDTO.getRegionIds());
        String url = rideLogService.rideLogCsvExportCsv(downloadDTO.getAccountId(), downloadDTO.getType(),
                downloadDTO.getStartTime().getTime(), downloadDTO.getEndTime().getTime(), downloadDTO.getPhone(), downloadDTO.getUserCode(),
                downloadDTO.getOrderNO(), role, regionList, downloadDTO.getTimeType(), downloadDTO.getRidingTimeMoreThan());
        return Result.success(url);
    }

    /**
     * 订单记录详细导出
     *
     * @param downloadDTO 入参
     * @return url
     */
    @RequestMapping("/rechargeQueryExportExcel")
    public Result<Object> rechargeQueryExport(RideLogDownloadDTO downloadDTO) {
        if (Objects.isNull(downloadDTO.getAccountId())) {
            return Result.error("ver.adAccountId.notNull");
        }
        if (Objects.isNull(downloadDTO.getStartTime())) {
            return Result.error("ver.startTime.notNull");
        }
        if (Objects.isNull(downloadDTO.getEndTime())) {
            return Result.error("ver.endTime.notNull");
        }
        LoginInfo login = tokenService.getLoginInfo(downloadDTO.getToken());
        Role role = login.getRoles().get(0);
        List<Integer> regionList = StringUtil.getIntegerList(downloadDTO.getRegionIds());
        return rideLogService.rideLogCsvExport(downloadDTO.getAccountId(), downloadDTO.getType(),
                downloadDTO.getStartTime().getTime(), downloadDTO.getEndTime().getTime(), downloadDTO.getPhone(), downloadDTO.getUserCode(),
                downloadDTO.getOrderNO(), role, regionList, downloadDTO.getTimeType(), downloadDTO.getRidingTimeMoreThan());
    }

    /**
     * @param rideLog
     * @return com.tbit.uqbike.object.view.JsonResult
     * @Description:骑行排行榜
     * @createDate 2020/11/23 13:38
     */
    @RequestMapping("/getRideRank")
    public JsonResult getRideRank(RideLog rideLog) {
        Assert.notNull(rideLog.getAccountId(), "ver.areaId.notNull");
        Assert.notNull(rideLog.getStartTime(), "sugar.startRideDt.notNull");
        Assert.notNull(rideLog.getEndTime(), "sugar.endRideDt.notNull");
        Assert.notNull(rideLog.getQuantity(), "please_enter_the_ranking");
        Page page = new Page(rideLog.getPageNO(), rideLog.getRowCount());
        PageHelperUtil.initPage(page);
        rideLog.setPage(page);
        PageInfo tops = new PageInfo(rideLogService.getRideRank(rideLog));
        if (null != rideLog.getQuantity() && tops.getTotal() > rideLog.getQuantity()) {
            tops.setTotal(rideLog.getQuantity());
        }
        return JsonResult.ok(tops.getList(), (int) tops.getTotal());
    }

    @RequestMapping("/excelRideRank")
    public JsonResult excelRideRank(RideLog rideLog, HttpServletResponse response) throws IOException {
        Assert.notNull(rideLog.getAccountId(), "ver.areaId.notNull");
        Assert.notNull(rideLog.getStartTime(), "sugar.startRideDt.notNull");
        Assert.notNull(rideLog.getEndTime(), "sugar.endRideDt.notNull");
        Assert.notNull(rideLog.getQuantity(), "please_enter_the_ranking");
        List<Map<String, Object>> data = rideLogService.getRideRank(rideLog);


        List<String> cellNameList = new ArrayList<>();
        int row = 1;
        String fileName = "用户骑行排行榜.xls";
        String title = "用户骑行排行榜";
        HSSFWorkbook excel = null;

        cellNameList.add("排名");
        cellNameList.add("用户名");
        cellNameList.add("手机号");
        cellNameList.add("借车总数");

        excel = Excel.createExcel(title, cellNameList);
        for (Map<String, Object> item : data) {
            List<String> excelData = new ArrayList<>();
            excelData.add(row + "");
            excelData.add(item.get("name") == null ? "" : item.get("name").toString());
            excelData.add(item.get("phone") == null ? "" : item.get("phone").toString());
            excelData.add(item.get("total") == null ? "" : item.get("total").toString());
            excel = Excel.createExcelData(excel, excelData, row);
            row++;
        }
        OutputStream out = null;
        String headStr = "attachment; filename=\"" + new String(fileName.getBytes("utf-8"), "ISO8859-1") + "\"";
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", headStr);
        out = response.getOutputStream();
        excel.write(out);
        out.flush();
        out.close();
        return JsonResult.ok();
    }

    /**
     * 订单金额修改 (弃用)
     */
    @PostMapping("/updateRidelog")
    @OperateLog(module = ModuleEnum.ORDER, methods = MethodEnum.ORDER_EDIT)
    public JsonResult updateRideLog(RideLog rideLog, HttpServletRequest request) {
        Assert.notNull(rideLog.getOrderNO(), "ver.orderNO.notNull");
        Assert.notNull(rideLog.getUserCode(), "usercode_is_not_null");
        Assert.notNull(rideLog.getRemark(), "remark_not_null");
        Assert.notNull(rideLog.getMoney(), "ver.money.notNull");
        //调用新接口，防止老接口被调用产生脏数据(罚款金额默认为0)
        Result result = rideLogDetailsService.editOrder(BaseController.getLogin(request), new EditOrderDTO(rideLog.getOrderNO(), rideLog.getMoney().longValue(), 0L, rideLog.getOperaPsw(), rideLog.getRemark()));
        if (HttpStatus.SUCCESS == result.getCode()) {
            return JsonResult.ok();
        } else {
            throw new BaseException(result.getMsg());
        }
    }

    /**
     * 根据车辆编号查询最近骑行用户
     *
     * @param machineId 设备id
     * @param accountId 运营区域id
     * @param pageNO    页码
     * @param rowCount  条数
     * @return Result<List < RideLog>>
     */
    @RequestMapping("/getRecentUser")
    public Result<List<RideLog>> getRecentUser(Integer machineId, Integer accountId,
                                               @RequestParam(defaultValue = "1") Integer pageNO,
                                               @RequestParam(defaultValue = "5") Integer rowCount) {
        Assert.notNull(machineId, "Machine.machineId.notNull");
        List<RideLog> rideLogList = rideLogService.getRecentUser(machineId, accountId, pageNO, rowCount);
        return Result.success(rideLogList);
    }

}